<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文本字数波浪线图分析工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">

    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        accent: '#8B5CF6',
                        dark: '#1F2937',
                        light: '#F3F4F6'
                    },
                    fontFamily: {
                        inter: ['Inter', 'sans-serif'],
                    },
                }
            }
        }
    </script>

    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .text-shadow {
                text-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
            .transition-custom {
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            }
            .wave-animation {
                animation: wave 3s infinite ease-in-out;
            }
            @keyframes wave {
                0%, 100% { transform: translateY(0); }
                50% { transform: translateY(-10px); }
            }
        }
    </style>
</head>
<body class="bg-gray-50 font-inter text-dark min-h-screen flex flex-col">
    <!-- 顶部导航栏 -->
    <header class="bg-white shadow-md sticky top-0 z-50 transition-all duration-300">
        <div class="container mx-auto px-4 py-4 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-bar-chart text-primary text-2xl"></i>
                <h1 class="text-xl md:text-2xl font-bold text-dark">文本字数波浪线图分析工具</h1>
            </div>
            <nav>
                <ul class="flex space-x-6">
                    <li><a href="#" class="text-gray-600 hover:text-primary transition-custom"><i class="fa fa-home mr-1"></i>首页</a></li>
                    <li><a href="#" class="text-gray-600 hover:text-primary transition-custom"><i class="fa fa-question-circle mr-1"></i>帮助</a></li>
                </ul>
            </nav>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="flex-grow container mx-auto px-4 py-8">
        <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
            <!-- 左侧面板 - 文件上传和文本输入 -->
            <div class="lg:col-span-1 space-y-6">
                <div class="bg-white rounded-xl shadow-lg p-6 transform hover:shadow-xl transition-custom">
                    <h2 class="text-lg font-semibold mb-4 flex items-center">
                        <i class="fa fa-file-text-o text-primary mr-2"></i>文件上传
                    </h2>
                    <div class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-primary transition-custom cursor-pointer" id="fileDropArea">
                        <i class="fa fa-cloud-upload text-4xl text-gray-400 mb-4"></i>
                        <p class="text-gray-500 mb-2">拖放文件到此处或</p>
                        <button class="bg-primary hover:bg-primary/90 text-white py-2 px-4 rounded-lg transition-custom">
                            <i class="fa fa-folder-open-o mr-1"></i> 选择文件
                        </button>
                        <input type="file" id="fileInput" class="hidden" accept=".txt,.js">
                        <p class="text-xs text-gray-400 mt-4">支持 .txt 和 .js 文件</p>
                    </div>
                </div>

                <div class="bg-white rounded-xl shadow-lg p-6 transform hover:shadow-xl transition-custom">
                    <h2 class="text-lg font-semibold mb-4 flex items-center">
                        <i class="fa fa-pencil-square-o text-primary mr-2"></i>文本输入
                    </h2>
                    <div class="mb-4">
                        <textarea id="textInput" rows="10" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-custom" placeholder="或者直接粘贴文本内容..."></textarea>
                    </div>
                    <div class="flex space-x-3">
                        <button id="analyzeBtn" class="flex-1 bg-primary hover:bg-primary/90 text-white py-2 px-4 rounded-lg transition-custom flex items-center justify-center">
                            <i class="fa fa-line-chart mr-2"></i> 分析文本
                        </button>
                        <button id="generateRandomBtn" class="bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 px-4 rounded-lg transition-custom">
                            <i class="fa fa-random"></i>
                        </button>
                    </div>
                </div>

                <div class="bg-white rounded-xl shadow-lg p-6 transform hover:shadow-xl transition-custom">
                    <h2 class="text-lg font-semibold mb-4 flex items-center">
                        <i class="fa fa-sliders text-primary mr-2"></i>图表设置
                    </h2>
                    <div class="space-y-4">
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">波浪动画</label>
                            <div class="flex items-center space-x-4">
                                <label class="inline-flex items-center">
                                    <input type="radio" name="animation" value="smooth" class="form-radio text-primary" checked>
                                    <span class="ml-2">平滑</span>
                                </label>
                                <label class="inline-flex items-center">
                                    <input type="radio" name="animation" value="wave" class="form-radio text-primary">
                                    <span class="ml-2">波浪</span>
                                </label>
                                <label class="inline-flex items-center">
                                    <input type="radio" name="animation" value="none" class="form-radio text-primary">
                                    <span class="ml-2">无</span>
                                </label>
                            </div>
                        </div>

                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">图表颜色</label>
                            <div class="grid grid-cols-4 gap-2">
                                <button class="color-option h-8 rounded-full bg-blue-500 border-2 border-white hover:border-gray-300 transition-custom" data-color="blue"></button>
                                <button class="color-option h-8 rounded-full bg-green-500 border-2 border-white hover:border-gray-300 transition-custom" data-color="green"></button>
                                <button class="color-option h-8 rounded-full bg-purple-500 border-2 border-white hover:border-gray-300 transition-custom" data-color="purple"></button>
                                <button class="color-option h-8 rounded-full bg-red-500 border-2 border-white hover:border-gray-300 transition-custom" data-color="red"></button>
                            </div>
                        </div>

                        <div>
                            <label for="pointSize" class="block text-sm font-medium text-gray-700 mb-1">点大小</label>
                            <input type="range" id="pointSize" min="2" max="10" value="6" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
                        </div>

                        <div>
                            <label for="lineWidth" class="block text-sm font-medium text-gray-700 mb-1">线宽</label>
                            <input type="range" id="lineWidth" min="1" max="5" value="2" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
                        </div>
                    </div>
                </div>
            </div>

            <!-- 右侧面板 - 分析结果和图表 -->
            <div class="lg:col-span-2 space-y-6">
                <div class="bg-white rounded-xl shadow-lg p-6 transform hover:shadow-xl transition-custom">
                    <h2 class="text-lg font-semibold mb-4 flex items-center">
                        <i class="fa fa-table text-primary mr-2"></i>分析结果
                    </h2>
                    <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
                        <div class="bg-blue-50 rounded-lg p-4 border-l-4 border-primary">
                            <p class="text-sm text-gray-500">总行数</p>
                            <p class="text-2xl font-bold text-primary" id="totalLines">0</p>
                        </div>
                        <div class="bg-green-50 rounded-lg p-4 border-l-4 border-green-500">
                            <p class="text-sm text-gray-500">平均字数</p>
                            <p class="text-2xl font-bold text-green-500" id="avgChars">-</p>
                        </div>
                        <div class="bg-purple-50 rounded-lg p-4 border-l-4 border-purple-500">
                            <p class="text-sm text-gray-500">最多字数</p>
                            <p class="text-2xl font-bold text-purple-500" id="maxChars">-</p>
                        </div>
                        <div class="bg-red-50 rounded-lg p-4 border-l-4 border-red-500">
                            <p class="text-sm text-gray-500">最少字数</p>
                            <p class="text-2xl font-bold text-red-500" id="minChars">-</p>
                        </div>
                    </div>

                    <div class="overflow-x-auto">
                        <table class="min-w-full divide-y divide-gray-200">
                            <thead class="bg-gray-50">
                                <tr>
                                    <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">行号</th>
                                    <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">字数</th>
                                    <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">内容预览</th>
                                </tr>
                            </thead>
                            <tbody id="linesTable" class="bg-white divide-y divide-gray-200 max-h-64 overflow-y-auto">
                                <!-- JavaScript 将动态填充表格内容 -->
                            </tbody>
                        </table>
                    </div>
                </div>

                <div class="bg-white rounded-xl shadow-lg p-6 transform hover:shadow-xl transition-custom">
                    <h2 class="text-lg font-semibold mb-4 flex items-center">
                        <i class="fa fa-area-chart text-primary mr-2"></i>字数波浪线图
                    </h2>
                    <div class="relative h-80">
                        <canvas id="waveChart"></canvas>
                    </div>
                </div>
            </div>
        </div>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark text-white py-6 mt-8">
        <div class="container mx-auto px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <p class="text-sm text-gray-400">&copy; 2025 文本分析工具 | 版权所有</p>
                </div>
                <div class="flex space-x-6">
                    <a href="#" class="text-gray-400 hover:text-white transition-custom">
                        <i class="fa fa-github text-xl"></i>
                    </a>
                    <a href="#" class="text-gray-400 hover:text-white transition-custom">
                        <i class="fa fa-twitter text-xl"></i>
                    </a>
                    <a href="#" class="text-gray-400 hover:text-white transition-custom">
                        <i class="fa fa-linkedin text-xl"></i>
                    </a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        // 全局变量
        let chart = null;
        let chartData = {
            labels: [],
            values: []
        };
        let chartColor = 'blue';

        // DOM 元素
        const fileDropArea = document.getElementById('fileDropArea');
        const fileInput = document.getElementById('fileInput');
        const textInput = document.getElementById('textInput');
        const analyzeBtn = document.getElementById('analyzeBtn');
        const generateRandomBtn = document.getElementById('generateRandomBtn');
        const linesTable = document.getElementById('linesTable');
        const totalLinesElement = document.getElementById('totalLines');
        const avgCharsElement = document.getElementById('avgChars');
        const maxCharsElement = document.getElementById('maxChars');
        const minCharsElement = document.getElementById('minChars');
        const colorOptions = document.querySelectorAll('.color-option');
        const pointSizeSlider = document.getElementById('pointSize');
        const lineWidthSlider = document.getElementById('lineWidth');

        // 文件拖放处理
        fileDropArea.addEventListener('dragover', (e) => {
            e.preventDefault();
            fileDropArea.classList.add('border-primary', 'bg-blue-50');
        });

        fileDropArea.addEventListener('dragleave', () => {
            fileDropArea.classList.remove('border-primary', 'bg-blue-50');
        });

        fileDropArea.addEventListener('drop', (e) => {
            e.preventDefault();
            fileDropArea.classList.remove('border-primary', 'bg-blue-50');

            if (e.dataTransfer.files.length) {
                const file = e.dataTransfer.files[0];
                if (isValidFile(file)) {
                    readFile(file);
                } else {
                    showNotification('请上传 .txt 或 .js 文件', 'error');
                }
            }
        });

        // 点击上传区域触发文件选择
        fileDropArea.addEventListener('click', () => {
            fileInput.click();
        });

        // 文件选择处理
        fileInput.addEventListener('change', () => {
            if (fileInput.files.length) {
                const file = fileInput.files[0];
                if (isValidFile(file)) {
                    readFile(file);
                } else {
                    showNotification('请上传 .txt 或 .js 文件', 'error');
                }
            }
        });

        // 分析按钮点击处理
        analyzeBtn.addEventListener('click', () => {
            const text = textInput.value.trim();
            if (text) {
                analyzeText(text);
            } else {
                showNotification('请输入文本内容或上传文件', 'warning');
            }
        });

        // 生成随机文本
        generateRandomBtn.addEventListener('click', () => {
            const randomText = generateRandomText(10, 30);
            textInput.value = randomText;
            analyzeText(randomText);
        });

        // 颜色选项点击处理
        colorOptions.forEach(option => {
            option.addEventListener('click', () => {
                // 移除所有选中状态
                colorOptions.forEach(opt => opt.classList.remove('border-2', 'border-gray-500'));
                // 添加选中状态
                option.classList.add('border-2', 'border-gray-500');
                // 更新颜色
                chartColor = option.dataset.color;
                // 重新绘制图表
                if (chartData.labels.length > 0) {
                    updateChart();
                }
            });
        });

        // 点大小滑块变化处理
        pointSizeSlider.addEventListener('input', () => {
            if (chartData.labels.length > 0) {
                updateChart();
            }
        });

        // 线宽滑块变化处理
        lineWidthSlider.addEventListener('input', () => {
            if (chartData.labels.length > 0) {
                updateChart();
            }
        });

        // 检查文件类型是否有效
        function isValidFile(file) {
            const validExtensions = ['txt', 'js'];
            const fileExtension = file.name.split('.').pop().toLowerCase();
            return validExtensions.includes(fileExtension);
        }

        // 读取文件内容
        function readFile(file) {
            const reader = new FileReader();

            reader.onload = (e) => {
                const content = e.target.result;
                textInput.value = content;
                analyzeText(content);
                showNotification(`已成功加载文件: ${file.name}`, 'success');
            };

            reader.onerror = () => {
                showNotification('读取文件时出错', 'error');
            };

            reader.readAsText(file);
        }

        // 分析文本内容
        function analyzeText(text) {
            // 分割文本行为数组，并过滤空行
            const lines = text.split('\n').filter(line => line.trim() !== '');

            if (lines.length === 0) {
                showNotification('没有找到有效的文本行', 'warning');
                return;
            }

            // 计算每行的字数
            const wordCounts = lines.map(line => line.length);

            // 更新数据
            chartData.labels = lines.map((_, index) => `行 ${index + 1}`);
            chartData.values = wordCounts;

            // 更新统计信息
            updateStatistics(wordCounts);

            // 更新表格
            updateTable(lines, wordCounts);

            // 更新图表
            updateChart();
        }

        // 更新统计信息
        function updateStatistics(wordCounts) {
            const totalLines = wordCounts.length;
            const totalChars = wordCounts.reduce((sum, count) => sum + count, 0);
            const avgChars = Math.round(totalChars / totalLines);
            const maxChars = Math.max(...wordCounts);
            const minChars = Math.min(...wordCounts);

            totalLinesElement.textContent = totalLines;
            avgCharsElement.textContent = avgChars;
            maxCharsElement.textContent = maxChars;
            minCharsElement.textContent = minChars;
        }

        // 更新表格
        function updateTable(lines, wordCounts) {
            linesTable.innerHTML = '';

            // 最多显示20行，避免表格过长
            const displayLines = lines.slice(0, 20);
            const displayCounts = wordCounts.slice(0, 20);

            displayLines.forEach((line, index) => {
                const row = document.createElement('tr');
                row.className = index % 2 === 0 ? 'bg-white' : 'bg-gray-50';

                // 预览文本，限制长度为50个字符
                const preview = line.length > 50 ? line.substring(0, 50) + '...' : line;

                row.innerHTML = `
                    <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${index + 1}</td>
                    <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${wordCounts[index]}</td>
                    <td class="px-6 py-4 text-sm text-gray-500">${preview}</td>
                `;

                linesTable.appendChild(row);
            });

            // 如果行数超过20，显示省略行
            if (lines.length > 20) {
                const row = document.createElement('tr');
                row.innerHTML = `
                    <td colspan="3" class="px-6 py-4 text-center text-sm text-gray-500">
                        共 ${lines.length} 行，仅显示前20行
                    </td>
                `;
                linesTable.appendChild(row);
            }
        }

        // 更新图表
        function updateChart() {
            const ctx = document.getElementById('waveChart').getContext('2d');

            // 获取颜色配置
            const colors = getChartColors(chartColor);

            // 获取动画类型
            const animationType = document.querySelector('input[name="animation"]:checked').value;

            // 波浪动画配置
            let animation = {
                duration: 1000,
                easing: 'easeOutQuart'
            };

            if (animationType === 'wave') {
                animation = {
                    duration: 2000,
                    easing: 'linear',
                    loop: true,
                    generateData: (chart) => {
                        const originalData = chart.data.datasets[0].data;
                        const t = Date.now() / 1000;
                        return originalData.map((value, index) => {
                            const x = index / originalData.length * Math.PI * 2;
                            return value + Math.sin(x + t) * 5;
                        });
                    }
                };
            } else if (animationType === 'none') {
                animation = {
                    duration: 0
                };
            }

            // 如果图表已存在，销毁它
            if (chart) {
                chart.destroy();
            }

            // 创建平滑的x值用于波浪线
            const smoothX = [];
            const smoothY = [];
            const points = 10; // 每个数据点之间的插值点数

            for (let i = 0; i < chartData.values.length - 1; i++) {
                for (let j = 0; j < points; j++) {
                    const t = j / points;
                    smoothX.push(i + t);
                    // 使用贝塞尔曲线插值
                    smoothY.push(chartData.values[i] + t * (chartData.values[i + 1] - chartData.values[i]));
                }
            }

            // 添加最后一个点
            smoothX.push(chartData.values.length - 1);
            smoothY.push(chartData.values[chartData.values.length - 1]);

            // 创建图表
            chart = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: smoothX.map((_, i) => i % points === 0 ? chartData.labels[Math.floor(i/points)] : ''),
                    datasets: [{
                        label: '字数',
                        data: smoothY,
                        borderColor: colors.border,
                        backgroundColor: colors.fill,
                        borderWidth: parseInt(lineWidthSlider.value),
                        pointBackgroundColor: colors.point,
                        pointBorderColor: '#fff',
                        pointBorderWidth: 1,
                        pointRadius: parseInt(pointSizeSlider.value),
                        pointHoverRadius: parseInt(pointSizeSlider.value) + 2,
                        tension: 0.4,
                        fill: true,
                        animation: animation
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: {
                            display: false
                        },
                        tooltip: {
                            backgroundColor: 'rgba(255, 255, 255, 0.9)',
                            titleColor: '#1F2937',
                            bodyColor: '#4B5563',
                            borderColor: '#E5E7EB',
                            borderWidth: 1,
                            padding: 12,
                            displayColors: false,
                            callbacks: {
                                label: function(context) {
                                    const index = Math.floor(context.dataIndex / points);
                                    if (index < chartData.labels.length) {
                                        return `${chartData.labels[index]}: ${chartData.values[index]} 字符`;
                                    }
                                    return '';
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            grid: {
                                display: false
                            },
                            ticks: {
                                maxRotation: 45,
                                minRotation: 45,
                                color: '#6B7280'
                            }
                        },
                        y: {
                            beginAtZero: true,
                            grid: {
                                color: '#E5E7EB'
                            },
                            ticks: {
                                color: '#6B7280'
                            }
                        }
                    },
                    interaction: {
                        mode: 'index',
                        intersect: false
                    }
                }
            });
        }

        // 获取图表颜色配置
        function getChartColors(color) {
            const colorConfig = {
                blue: {
                    border: '#3B82F6',
                    fill: 'rgba(59, 130, 246, 0.1)',
                    point: '#3B82F6'
                },
                green: {
                    border: '#10B981',
                    fill: 'rgba(16, 185, 129, 0.1)',
                    point: '#10B981'
                },
                purple: {
                    border: '#8B5CF6',
                    fill: 'rgba(139, 92, 246, 0.1)',
                    point: '#8B5CF6'
                },
                red: {
                    border: '#EF4444',
                    fill: 'rgba(239, 68, 68, 0.1)',
                    point: '#EF4444'
                }
            };

            return colorConfig[color] || colorConfig.blue;
        }

        // 生成随机文本
        function generateRandomText(minLines = 5, maxLines = 20, minChars = 1, maxChars = 50) {
            const linesCount = Math.floor(Math.random() * (maxLines - minLines + 1)) + minLines;
            const lines = [];

            for (let i = 0; i < linesCount; i++) {
                const charsCount = Math.floor(Math.random() * (maxChars - minChars + 1)) + minChars;
                let line = '';

                for (let j = 0; j < charsCount; j++) {
                    // 随机生成数字或字母
                    const charCode = Math.floor(Math.random() * 36);
                    line += charCode < 10
                        ? charCode.toString()
                        : String.fromCharCode(charCode + 87);
                }

                lines.push(line);
            }

            return lines.join('\n');
        }

        // 显示通知
        function showNotification(message, type = 'info') {
            // 检查是否已存在通知元素
            let notification = document.querySelector('.notification');
            if (notification) {
                notification.remove();
            }

            // 创建通知元素
            notification = document.createElement('div');
            notification.className = 'notification fixed top-4 right-4 px-6 py-3 rounded-lg shadow-lg z-50 transition-all duration-300 transform translate-x-full';

            // 设置通知类型样式
            if (type === 'success') {
                notification.classList.add('bg-green-50', 'border-l-4', 'border-green-500', 'text-green-700');
                notification.innerHTML = `
                    <div class="flex items-center">
                        <i class="fa fa-check-circle text-green-500 mr-3 text-xl"></i>
                        <p>${message}</p>
                    </div>
                `;
            } else if (type === 'error') {
                notification.classList.add('bg-red-50', 'border-l-4', 'border-red-500', 'text-red-700');
                notification.innerHTML = `
                    <div class="flex items-center">
                        <i class="fa fa-exclamation-circle text-red-500 mr-3 text-xl"></i>
                        <p>${message}</p>
                    </div>
                `;
            } else if (type === 'warning') {
                notification.classList.add('bg-yellow-50', 'border-l-4', 'border-yellow-500', 'text-yellow-700');
                notification.innerHTML = `
                    <div class="flex items-center">
                        <i class="fa fa-exclamation-triangle text-yellow-500 mr-3 text-xl"></i>
                        <p>${message}</p>
                    </div>
                `;
            } else {
                notification.classList.add('bg-blue-50', 'border-l-4', 'border-blue-500', 'text-blue-700');
                notification.innerHTML = `
                    <div class="flex items-center">
                        <i class="fa fa-info-circle text-blue-500 mr-3 text-xl"></i>
                        <p>${message}</p>
                    </div>
                `;
            }

            // 添加到页面
            document.body.appendChild(notification);

            // 显示通知
            setTimeout(() => {
                notification.classList.remove('translate-x-full');
            }, 10);

            // 自动关闭
            setTimeout(() => {
                notification.classList.add('translate-x-full');
                setTimeout(() => {
                    notification.remove();
                }, 300);
            }, 3000);
        }

        // 初始化示例数据
        document.addEventListener('DOMContentLoaded', () => {
            // 设置默认颜色选择
            colorOptions[0].classList.add('border-2', 'border-gray-500');

            // 生成一些示例数据
            const sampleText = `1234a
123456
123456789
123
1234334
123232314324324
1233421343223432`;

            textInput.value = sampleText;
            analyzeText(sampleText);
        });
    </script>
</body>
</html>